/*
 * Copyright (C) 2017 Intel Corporation.  All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */

// Copyright (c) WanSheng Intelligent Corp. All rights reserved.


#define LOG_TAG "AMS"

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include "ams_constants.h"
#include "ams_path.h"
#include "misc.h"
#include "path.h"
#include "logs.h"

static char * g_product_name = NULL;
static char path_buffer[PATH_LEN] = {0};
static char * g_product_root = NULL;

char * ams_path_internal_buf()
{
    return path_buffer;
}

/*
product name: a software product use it to locate its own configurations

a few ways to set:
- the software can call ams_set_product_name() to set it.
- it can be configured in the product.ams file under the product root dir
- it can be defined in AMS_PRODUCT_NAME during compilation (prefered)
*/

bool ams_set_product_name(char * name)
{
    log_print(LOG_TAG,"ams_set_product_name: %s\n", name);
    if(g_product_name) free(g_product_name);
    g_product_name = strdup(name);
    return true;
}

const char * get_product_name()
{
    if(g_product_name)
        return g_product_name;
    #ifdef AMS_PRODUCT_NAME
    return MACRO_STR(AMS_PRODUCT_NAME);
    #else
    return NULL;
    #endif
}

/*
 * Under the root dir of each product, there is a file "product.ams"
 * That is used to identify the root dir.
 */
#define PRODUCT_FILE "product.ams"

// set the root dir for the current product
bool ams_set_product_root(char * root_dir)
{
    if(g_product_root) free(g_product_root);
    int len = strlen(root_dir);
    if(len == 0)
        return false;

    g_product_root = (char*) malloc(len + 2);
    if(!g_product_root) return false;

    strcpy(g_product_root, root_dir);
    
    if(g_product_root[len-1] != '/')
    {
        g_product_root[len] = '/';
        g_product_root[len+1] = 0;
    }

    log_print(LOG_TAG, "ams_set_product_root: %s", g_product_root);
    printf("ams_set_product_root: %s\n", g_product_root);
    return true;
}

// the path derived from the binary path. 
// located upper directory with product.ams as root dir.
const char* ams_get_running_root()
{
    return g_product_root;
}
 
// bin_path: the binary path
// both g_product_root and bin_path will  end with '/'
bool ams_locate_product_path(char * execpath, char * bin_path)
{
    char path[PATH_LEN] ;
    strcpy(path, execpath);
    printf("enter %s: execpath=%s\n", __FUNCTION__, execpath);

    // the ams client default dir is current binary folder
    strcpy(path, execpath);
    char * p = strrchr(path, '/'); // remove *.so
    if(p)
    {
        *(p+1) = 0;
        if(bin_path) strcpy(bin_path, path);
    }
    else
    {
        return false;
    }
    
    strcpy(path, execpath);
    p = strrchr(path, '/');
    while(p)
    {
        strcpy(p+1, PRODUCT_FILE);
        if(access(path, F_OK) == 0)
        {
            char product_name[256];
            if(read_ini_key(path, PRODUCT_KEY, product_name, sizeof(product_name)))
            {
                ams_set_product_name(product_name);
            }

            *(p) = 0;
            ams_set_product_root(path);
            return true;
        }

        // back to upper dir
        *(p) = 0;
        p = strrchr(path, '/');
    }

    return false;
}


char * ams_get_temp_root(char * dir, int buf_len)
{
    strncpy(dir, get_ams_root_dir(), buf_len-1);
    strncat(dir, "temp/", buf_len -1);
    const char * product = get_product_name();
    if(product)
    {
        strncat(dir, product, buf_len - 1);
        strncat(dir,"/", buf_len - 1);
    }
    dir[buf_len - 1] = 0;
    return dir;
}

char * ams_make_temp_dir(char * dir, char * subdir)
{
    char path[PATH_LEN] = {0};
    char * p = ams_get_temp_root(path, sizeof(path));
    if(subdir)
        strcat(p, subdir);
    else
        strcat(p, "dir");

    strncpy(path, p, sizeof(path)-1);
    int i = 1;
    while (0 == access(path, 0) && i < 10000)
    {
        //file exists;
        sprintf(path, "%s_%d", p, i);
        i++;
    }

    if(i == 10000)
        return NULL;

    if(dir == NULL) dir = &path_buffer[0];
    strcpy(dir, path);
    strcat(dir, "/");
    return dir;
}

char * ams_get_temp_pathname(char * pathname, const char * prefix)
{
    char path[PATH_LEN] = {0};
    char * p = ams_get_temp_root(path, sizeof(path));
    if(prefix)
        strcat(p, prefix);
    else
        strcat(p, "file");

    int i = 1;
    while (0 == access(path, 0) && i < 10000)
    {
        //file exists;
        sprintf(path, "%s_%d", p, i);
        i++;
    }

    if(i == 10000)
        return NULL;

    if(pathname == NULL) pathname = &path_buffer[0];
    strcpy(pathname, path);

    return pathname;
}

char * ams_my_product_root(char * buf, int buf_len)
{
    char *path = buf;
    if(path == NULL) 
    {
        path = &path_buffer[0];
        buf_len = sizeof(path_buffer);
    }
    const char * product = get_product_name();
    if(product)
    {
        char * p = get_sw_product_root(product, path);
        printf("ams_my_product_root: product=%s, path=%s\n", product, p);
        return p;
    }
    else if(g_product_root)
    {
        strncpy(path, g_product_root, buf_len -1);
        path[buf_len -1] = 0;
        return path;
    }
    else
    {
        strncpy(path, get_bin_path(), buf_len -1);
        path[buf_len -1] = 0;
        return path;
    }
}



char * ams_get_product_scripts_dir(char * path)
{
    ams_my_product_root(path, PATH_LEN);
    strcat(path, "ams/triggers/");
    return path;
}



char * get_sw_product_root(const char * product, char * path)
{
	if(path == NULL) path = ams_path_internal_buf();
	strcpy(path, get_ams_root_dir());
	strcat(path, product);
	strcat(path, "/");
	return path;
}

char * get_sw_product_dir(const char * product, char * path)
{
	if(path == NULL) path = ams_path_internal_buf();
	strcpy(path, get_ams_root_dir());
	strcat(path, product);
	strcat(path, "/product/");
	return path;
}


char * get_sw_product_config_dir(const char * product, char * path)
{
	if(path == NULL) path = ams_path_internal_buf();
	get_sw_product_root(product, path);
	strcat(path, "config/");
	return path;
}


char * get_sw_product_scripts_dir(const char * product, char * path)
{
	if(path == NULL) path = ams_path_internal_buf();
	get_sw_product_root(product, path);
	strcat(path, "product/ams/triggers/");
	return path;
}

char * get_sw_product_config_pathname(
        const char * product_name,
        char * target_type,
        char * target_id,
        char * out_path)
{
    if(out_path == NULL) out_path = ams_path_internal_buf();
    get_sw_product_config_dir(product_name,out_path);
    strcat(out_path, target_type);
    if((strcmp(TT_DEVICE,target_type) != 0)&& target_id && *target_id != 0)
    {
        strcat(out_path, "/");
        strcat(out_path, target_id);
    }
    return out_path;
}

